home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / info-service / www / src / WWW / Library / Implementation / HTAccess.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-14  |  17.2 KB  |  683 lines

  1. /*        Access Manager                    HTAccess.c
  2. **        ==============
  3. **
  4. ** Authors
  5. **    TBL    Tim Berners-Lee timbl@info.cern.ch
  6. **    JFG    Jean-Francois Groff jfg@dxcern.cern.ch
  7. **    DD    Denis DeLaRoca (310) 825-4580  <CSP1DWD@mvs.oac.ucla.edu>
  8. ** History
  9. **       8 Jun 92 Telnet hopping prohibited as telnet is not secure TBL
  10. **    26 Jun 92 When over DECnet, suppressed FTP, Gopher and News. JFG
  11. **     6 Oct 92 Moved HTClientHost and logfile into here. TBL
  12. **    17 Dec 92 Tn3270 added, bug fix. DD
  13. **     4 Feb 93 Access registration, Search escapes bad chars TBL
  14. **          PARAMETERS TO HTSEARCH AND HTLOADRELATIVE CHANGED
  15. **    28 May 93 WAIS gateway explicit if no WAIS library linked in.
  16. **
  17. ** Bugs
  18. **    This module assumes that that the graphic object is hypertext, as it
  19. **    needs to select it when it has been loaded.  A superclass needs to be
  20. **    defined which accepts select and select_anchor.
  21. */
  22.  
  23. #ifndef DEFAULT_WAIS_GATEWAY
  24. #define DEFAULT_WAIS_GATEWAY "http://info.cern.ch:8001/"
  25. #endif
  26.  
  27. /* Implements:
  28. */
  29. #include "HTAccess.h"
  30.  
  31. /* Uses:
  32. */
  33.  
  34. #include "HTParse.h"
  35. #include "HTUtils.h"
  36. #include "HTML.h"        /* SCW */
  37.  
  38. #ifndef NO_RULES
  39. #include "HTRules.h"
  40. #endif
  41.  
  42. #include <stdio.h>
  43.  
  44. #include "HTList.h"
  45. #include "HText.h"    /* See bugs above */
  46. #include "HTAlert.h"
  47.  
  48.  
  49. /*    These flags may be set to modify the operation of this module
  50. */
  51. PUBLIC char * HTClientHost = 0;    /* Name of remote login host if any */
  52. PUBLIC FILE * logfile = 0;    /* File to which to output one-liners */
  53. PUBLIC BOOL HTSecure = NO;    /* Disable access for telnet users? */
  54.  
  55. /*    To generate other things, play with these:
  56. */
  57.  
  58. PUBLIC HTFormat HTOutputFormat = NULL;
  59. PUBLIC HTStream* HTOutputStream = NULL;    /* For non-interactive, set this */ 
  60.  
  61. PRIVATE HTList * protocols = NULL;   /* List of registered protocol descriptors */
  62.  
  63.  
  64. /*    Register a Protocol                HTRegisterProtocol
  65. **    -------------------
  66. */
  67.  
  68. PUBLIC BOOL HTRegisterProtocol(protocol)
  69.     HTProtocol * protocol;
  70. {
  71.     if (!protocols) protocols = HTList_new();
  72.     HTList_addObject(protocols, protocol);
  73.     return YES;
  74. }
  75.  
  76.  
  77. /*    Register all known protocols
  78. **    ----------------------------
  79. **
  80. **    Add to or subtract from this list if you add or remove protocol modules.
  81. **    This routine is called the first time the protocol list is needed,
  82. **    unless any protocols are already registered, in which case it is not called.
  83. **    Therefore the application can override this list.
  84. **
  85. **    Compiling with NO_INIT prevents all known protocols from being forced
  86. **    in at link time.
  87. */
  88. #ifndef NO_INIT
  89. PRIVATE void HTAccessInit NOARGS            /* Call me once */
  90. {
  91. extern HTProtocol HTTP, HTFile, HTTelnet, HTTn3270, HTRlogin;
  92. #ifndef DECNET
  93. extern HTProtocol HTFTP, HTNews, HTGopher;
  94. #ifdef DIRECT_WAIS
  95. extern HTProtocol HTWAIS;
  96. #endif
  97.     HTRegisterProtocol(&HTFTP);
  98.     HTRegisterProtocol(&HTNews);
  99.     HTRegisterProtocol(&HTGopher);
  100. #ifdef DIRECT_WAIS
  101.     HTRegisterProtocol(&HTWAIS);
  102. #endif
  103. #endif
  104.  
  105.     HTRegisterProtocol(&HTTP);
  106.     HTRegisterProtocol(&HTFile);
  107.     HTRegisterProtocol(&HTTelnet);
  108.     HTRegisterProtocol(&HTTn3270);
  109.     HTRegisterProtocol(&HTRlogin);
  110. }
  111. #endif
  112.  
  113.  
  114. /*        Find physical name and access protocol
  115. **        --------------------------------------
  116. **
  117. **
  118. ** On entry,
  119. **    addr        must point to the fully qualified hypertext reference.
  120. **    anchor        a pareent anchor with whose address is addr
  121. **
  122. ** On exit,
  123. **    returns        HT_NO_ACCESS        Error has occured.
  124. **            HT_OK            Success
  125. **
  126. */
  127. PRIVATE int get_physical ARGS2(
  128.     CONST char *,        addr,
  129.     HTParentAnchor *,    anchor)
  130. {
  131.     char * access=0;    /* Name of access method */
  132.     char * physical = 0;
  133.     
  134. #ifndef NO_RULES
  135.     physical = HTTranslate(addr);
  136.     if (!physical) {
  137.     return HT_FORBIDDEN;
  138.     }
  139.     HTAnchor_setPhysical(anchor, physical);
  140.     free(physical);            /* free our copy */
  141. #else
  142.     HTAnchor_setPhysical(anchor, addr);
  143. #endif
  144.  
  145.     access =  HTParse(HTAnchor_physical(anchor),
  146.             "file:", PARSE_ACCESS);
  147.  
  148. /*    Check whether gateway access has been set up for this
  149. **
  150. **    This function can be replaced by the rule system above.
  151. */
  152. #define USE_GATEWAYS
  153. #ifdef USE_GATEWAYS
  154.     {
  155.     char * gateway_parameter, *gateway;
  156.     gateway_parameter = (char *)malloc(strlen(access)+20);
  157.     if (gateway_parameter == NULL) outofmem(__FILE__, "HTLoad");
  158.     strcpy(gateway_parameter, "WWW_");
  159.     strcat(gateway_parameter, access);
  160.     strcat(gateway_parameter, "_GATEWAY");
  161.     gateway = (char *)getenv(gateway_parameter); /* coerce for decstation */
  162.     free(gateway_parameter);
  163.     
  164. #ifndef DIRECT_WAIS
  165.     if (!gateway && 0==strcmp(access, "wais")) {
  166.         gateway = DEFAULT_WAIS_GATEWAY;
  167.     }
  168. #endif
  169.     if (gateway) {
  170.         char * path = HTParse(addr, "",
  171.             PARSE_HOST + PARSE_PATH + PARSE_PUNCTUATION);
  172.         /* Chop leading / off to make host into part of path */
  173.         char * gatewayed = HTParse(path+1, gateway, PARSE_ALL);
  174.         free(path);
  175.             HTAnchor_setPhysical(anchor, gatewayed);
  176.         free(gatewayed);
  177.         free(access);
  178.         
  179.             access =  HTParse(HTAnchor_physical(anchor),
  180.             "http:", PARSE_ACCESS);
  181.     }
  182.     }
  183. #endif
  184.  
  185.  
  186.  
  187. /*    Search registered protocols to find suitable one
  188. */
  189.     {
  190.     int i, n;
  191. #ifndef NO_INIT
  192.         if (!protocols) HTAccessInit();
  193. #endif
  194.     n = HTList_count(protocols);
  195.     for (i=0; i<n; i++) {
  196.         HTProtocol *p = HTList_objectAt(protocols, i);
  197.         if (strcmp(p->name, access)==0) {
  198.         HTAnchor_setProtocol(anchor, p);
  199.         free(access);
  200.         return (HT_OK);
  201.         }
  202.     }
  203.     }
  204.  
  205.     free(access);
  206.     return HT_NO_ACCESS;
  207. }
  208.  
  209.  
  210. /*        Load a document
  211. **        ---------------
  212. **
  213. **    This is an internal routine, which has an address AND a matching
  214. **    anchor.  (The public routines are called with one OR the other.)
  215. **
  216. ** On entry,
  217. **    addr        must point to the fully qualified hypertext reference.
  218. **    anchor        a pareent anchor with whose address is addr
  219. **
  220. ** On exit,
  221. **    returns        <0        Error has occured.
  222. **            HT_LOADED    Success
  223. **            HT_NO_DATA    Success, but no document loaded.
  224. **                    (telnet sesssion started etc)
  225. **
  226. */
  227. PRIVATE int HTLoad ARGS4(
  228.     CONST char *,        addr,
  229.     HTParentAnchor *,    anchor,
  230.     HTFormat,        format_out,
  231.     HTStream *,        sink)
  232. {
  233.     HTProtocol* p;
  234.     int status = get_physical(addr, anchor);
  235.     if (status == HT_FORBIDDEN) {
  236.         return HTLoadError(sink, 500, "Access forbidden by rule");
  237.     }
  238.     if (status < 0) return status;    /* Can't resolve or forbidden */
  239.     
  240.     p = HTAnchor_protocol(anchor);
  241.     return (*(p->load))(HTAnchor_physical(anchor),
  242.                 anchor, format_out, sink);
  243. }
  244.  
  245.  
  246. /*        Get a save stream for a document
  247. **        --------------------------------
  248. */
  249. PUBLIC HTStream *HTSaveStream ARGS1(HTParentAnchor *, anchor)
  250. {
  251.     HTProtocol * p = HTAnchor_protocol(anchor);
  252.     if (!p) return NULL;
  253.     
  254.     return (*p->saveStream)(anchor);
  255.     
  256. }
  257.  
  258.  
  259. /*        Load a document - with logging etc
  260. **        ----------------------------------
  261. **
  262. **    - Checks or documents already loaded
  263. **    - Logs the access
  264. **    - Allows stdin filter option
  265. **    - Trace ouput and error messages
  266. **
  267. **    On Entry,
  268. **      anchor        is the node_anchor for the document
  269. **        full_address      The address of the document to be accessed.
  270. **        filter            if YES, treat stdin as HTML
  271. **
  272. **    On Exit,
  273. **        returns    YES     Success in opening document
  274. **                   NO      Failure 
  275. **
  276. */
  277.  
  278. PRIVATE BOOL HTLoadDocument ARGS4(
  279.     CONST char *,        full_address,
  280.     HTParentAnchor *,    anchor,
  281.     HTFormat,        format_out,
  282.     HTStream*,        sink)
  283.  
  284. {
  285.     int            status;
  286.     HText *    text;
  287.  
  288.     if (TRACE) fprintf (stderr,
  289.       "HTAccess: loading document %s\n", full_address);
  290.  
  291.     if (text=(HText *)HTAnchor_document(anchor)) {    /* Already loaded */
  292.         if (TRACE) fprintf(stderr, "HTAccess: Document already in memory.\n");
  293.         HText_select(text);
  294.     return YES;
  295.     }
  296.     
  297.     status = HTLoad(full_address, anchor, format_out, sink);
  298.  
  299.     
  300. /*    Log the access if necessary
  301. */
  302.     if (logfile) {
  303.     time_t theTime;
  304.     time(&theTime);
  305.     fprintf(logfile, "%24.24s %s %s %s\n",
  306.         ctime(&theTime),
  307.         HTClientHost ? HTClientHost : "local",
  308.         status<0 ? "FAIL" : "GET",
  309.         full_address);
  310.     fflush(logfile);    /* Actually update it on disk */
  311.     if (TRACE) fprintf(stderr, "Log: %24.24s %s %s %s\n",
  312.         ctime(&theTime),
  313.         HTClientHost ? HTClientHost : "local",
  314.         status<0 ? "FAIL" : "GET",
  315.         full_address);
  316.     }
  317.     
  318.  
  319.     if (status == HT_LOADED) {
  320.     if (TRACE) {
  321.         fprintf(stderr, "HTAccess: `%s' has been accessed.\n",
  322.         full_address);
  323.     }
  324.     return YES;
  325.     }
  326.     
  327.     if (status == HT_NO_DATA) {
  328.     if (TRACE) {
  329.         fprintf(stderr, 
  330.         "HTAccess: `%s' has been accessed, No data left.\n",
  331.         full_address);
  332.     }
  333.     return NO;
  334.     }
  335.     
  336.     if (status<0) {              /* Failure in accessing a document */
  337. #ifdef CURSES
  338.         user_message("Can't access `%s'", full_address);
  339. #else
  340.     if (TRACE) fprintf(stderr, 
  341.         "HTAccess: Can't access `%s'\n", full_address);
  342. #endif
  343.     HTLoadError(sink, 500, "Unable to access document.");
  344.     return NO;
  345.     }
  346.  
  347.     /* If you get this, then please find which routine is returning
  348.        a positive unrecognised error code! */
  349.  
  350.     fprintf(stderr,
  351.     "**** HTAccess: socket or file number returned by obsolete load routine!\n");
  352.     fprintf(stderr,
  353.     "**** HTAccess: Internal software error. Please mail www-bug@info.cern.ch!\n");
  354.     exit(-6996);
  355.  
  356. } /* HTLoadDocument */
  357.  
  358.  
  359.  
  360. /*        Load a document from absolute name
  361. **        ---------------
  362. **
  363. **    On Entry,
  364. **        addr     The absolute address of the document to be accessed.
  365. **        filter   if YES, treat document as HTML
  366. **
  367. **    On Exit,
  368. **        returns    YES     Success in opening document
  369. **                   NO      Failure 
  370. **
  371. **
  372. */
  373.  
  374. PUBLIC BOOL HTLoadAbsolute ARGS1(CONST char *,addr)
  375. {
  376.    return HTLoadDocument( addr,
  377.                HTAnchor_parent(HTAnchor_findAddress(addr)),
  378.                    HTOutputFormat ? HTOutputFormat : WWW_PRESENT,
  379.             HTOutputStream);
  380. }
  381.  
  382.  
  383. /*        Load a document from absolute name to stream
  384. **        --------------------------------------------
  385. **
  386. **    On Entry,
  387. **        addr     The absolute address of the document to be accessed.
  388. **        sink     if non-NULL, send data down this stream
  389. **
  390. **    On Exit,
  391. **        returns    YES     Success in opening document
  392. **                   NO      Failure 
  393. **
  394. **
  395. */
  396.  
  397. PUBLIC BOOL HTLoadToStream ARGS3(
  398.         CONST char *,    addr,
  399.         BOOL,         filter,
  400.         HTStream *,     sink)
  401. {
  402.    return HTLoadDocument(addr,
  403.                HTAnchor_parent(HTAnchor_findAddress(addr)),
  404.                    HTOutputFormat ? HTOutputFormat : WWW_PRESENT,
  405.             sink);
  406. }
  407.  
  408.  
  409.  
  410.  
  411. /*        Load a document from relative name
  412. **        ---------------
  413. **
  414. **    On Entry,
  415. **        relative_name     The relative address of the document
  416. **                  to be accessed.
  417. **
  418. **    On Exit,
  419. **        returns    YES     Success in opening document
  420. **                   NO      Failure 
  421. **
  422. **
  423. */
  424.  
  425. PUBLIC BOOL HTLoadRelative ARGS2(
  426.         CONST char *,        relative_name,
  427.         HTParentAnchor *,    here)
  428. {
  429.     char *         full_address = 0;
  430.     BOOL               result;
  431.     char *         mycopy = 0;
  432.     char *         stripped = 0;
  433.     char *        current_address =
  434.                     HTAnchor_address((HTAnchor*)here);
  435.  
  436.     StrAllocCopy(mycopy, relative_name);
  437.  
  438.     stripped = HTStrip(mycopy);
  439.     full_address = HTParse(stripped,
  440.                current_address,
  441.            PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
  442.     result = HTLoadAbsolute(full_address);
  443.     free(full_address);
  444.     free(current_address);
  445.     free(mycopy);  /* Memory leak fixed 10/7/92 -- JFG */
  446.     return result;
  447. }
  448.  
  449.  
  450. /*        Load if necessary, and select an anchor
  451. **        --------------------------------------
  452. **
  453. **    On Entry,
  454. **        destination              The child or parenet anchor to be loaded.
  455. **
  456. **    On Exit,
  457. **        returns    YES     Success
  458. **                   NO      Failure 
  459. **
  460. */
  461.  
  462. PUBLIC BOOL HTLoadAnchor ARGS1(HTAnchor *,destination)
  463. {
  464.     HTParentAnchor * parent;
  465.     BOOL loaded = NO;
  466.     if (!destination) return NO;    /* No link */
  467.     
  468.     parent  = HTAnchor_parent(destination);
  469.     
  470.     if (HTAnchor_document(parent) == NULL) {    /* If not alread loaded */
  471.                             /* TBL 921202 */
  472.  
  473.         BOOL result;
  474.         char * address = HTAnchor_address((HTAnchor*) parent);
  475.     result = HTLoadDocument(address, parent,
  476.         HTOutputFormat ? HTOutputFormat : WWW_PRESENT,
  477.         HTOutputStream);
  478.     free(address);
  479.     if (!result) return NO;
  480.     loaded = YES;
  481.     }
  482.     
  483.     {
  484.     HText *text = (HText*)HTAnchor_document(parent);
  485.     if (destination != (HTAnchor *)parent) {  /* If child anchor */
  486.         HText_selectAnchor(text, 
  487.             (HTChildAnchor*)destination); /* Double display? @@ */
  488.     } else {
  489.         if (!loaded) HText_select(text);
  490.     }
  491.     }
  492.     return YES;
  493.     
  494. } /* HTLoadAnchor */
  495.  
  496.  
  497. /*        Search
  498. **        ------
  499. **  Performs a keyword search on word given by the user. Adds the keyword to 
  500. **  the end of the current address and attempts to open the new address.
  501. **
  502. **  On Entry,
  503. **       *keywords      space-separated keyword list or similar search list
  504. **    here        is anchor search is to be done on.
  505. */
  506.  
  507. PRIVATE char hex(i)
  508.     int i;
  509. {
  510.     return i < 10 ? '0'+i : 'A'+ i - 10;
  511. }
  512.  
  513. PUBLIC BOOL HTSearch ARGS2(
  514.     CONST char *,         keywords,
  515.     HTParentAnchor *,     here)
  516. {
  517.  
  518. #define acceptable \
  519. "1234567890abcdefghijlkmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-_"
  520.  
  521.     char *q, *u;
  522.     CONST char * p, *s, *e;        /* Pointers into keywords */
  523.     char * address = HTAnchor_address((HTAnchor*)here);
  524.     BOOL result;
  525.     char * escaped = malloc(strlen(keywords)*3+1);
  526.  
  527.     static CONST BOOL isAcceptable[96] =
  528.  
  529.     /*   0 1 2 3 4 5 6 7 8 9 A B C D E F */
  530.     {    0,0,0,0,0,0,0,0,0,0,1,0,0,1,1,0,    /* 2x   !"#$%&'()*+,-./     */
  531.          1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,    /* 3x  0123456789:;<=>?     */
  532.      1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,    /* 4x  @ABCDEFGHIJKLMNO  */
  533.      1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,    /* 5X  PQRSTUVWXYZ[\]^_     */
  534.      0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,    /* 6x  `abcdefghijklmno     */
  535.      1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0 };    /* 7X  pqrstuvwxyz{\}~    DEL */
  536.  
  537.     if (escaped == NULL) outofmem(__FILE__, "HTSearch");
  538.     
  539.  
  540. /*    Convert spaces to + and hex escape unacceptable characters
  541. */
  542.     for(s=keywords; *s && WHITE(*s); s++) /*scan */ ;    /* Skip white space */
  543.     for(e = s + strlen(s); e>s && WHITE(*(e-1)) ; e--); /* Skip trailers */
  544.     for(q=escaped, p=s; p<e; p++) {            /* scan stripped field */
  545.         int c = (int)TOASCII(*p);
  546.         if (WHITE(*p)) {
  547.         *q++ = '+';
  548.     } else if (c>=32 && c<=(char)127 && isAcceptable[c-32]) {
  549.         *q++ = (char)c;
  550.     } else {
  551.         *q++ = '%';
  552.         *q++ = hex(c / 16);
  553.         *q++ = hex(c % 16);
  554.     }
  555.     } /* Loop over string */
  556.     
  557.     *q=0;
  558.                     /* terminate escaped sctring */
  559.     u=strchr(address, '?');        /* Find old search string */
  560.     if (u) *u = 0;                    /* Chop old search off */
  561.  
  562.     StrAllocCat(address, "?");
  563.     StrAllocCat(address, escaped);
  564.     free(escaped);
  565.     result = HTLoadRelative(address, here);
  566.     free(address);
  567.     
  568.     return result;
  569. }
  570.  
  571.  
  572. /*        Search Given Indexname
  573. **        ------
  574. **  Performs a keyword search on word given by the user. Adds the keyword to 
  575. **  the end of the current address and attempts to open the new address.
  576. **
  577. **  On Entry,
  578. **       *keywords      space-separated keyword list or similar search list
  579. **    *addres        is name of object search is to be done on.
  580. */
  581.  
  582. PUBLIC BOOL HTSearchAbsolute ARGS2(
  583.     CONST char *,     keywords,
  584.     CONST char *,     indexname)
  585. {
  586.     HTParentAnchor * anchor =
  587.         (HTParentAnchor*) HTAnchor_findAddress(indexname);
  588.     return HTSearch(keywords, anchor);
  589. }
  590.  
  591.  
  592. /*        Generate the anchor for the home page
  593. **        -------------------------------------
  594. **
  595. **    As it involves file access, this should only be done once
  596. **    when the program first runs.
  597. **    This is a default algorithm -- browser don't HAVE to use this.
  598. **    But consistency betwen browsers is STRONGLY recommended!
  599. **
  600. **    Priority order is:
  601. **
  602. **        1    WWW_HOME environment variable (logical name, etc)
  603. **        2    ~/WWW/default.html
  604. **        3    /usr/local/bin/default.html
  605. **        4    http://info.cern.ch/default.html
  606. **
  607. */
  608. PUBLIC HTParentAnchor * HTHomeAnchor NOARGS
  609. {
  610.     char * my_home_document = NULL;
  611.     char * home = (char *)getenv(LOGICAL_DEFAULT);
  612.     char * ref;
  613.     HTParentAnchor * anchor;
  614.     
  615.     if (home) {
  616.         StrAllocCopy(my_home_document, home);
  617.     
  618. /*     Someone telnets in, they get a special home.
  619. */
  620. #define MAX_FILE_NAME 1024                    /* @@@ */
  621.     } else  if (HTClientHost) {            /* Telnet server */
  622.         FILE * fp = fopen(REMOTE_POINTER, "r");
  623.     char * status;
  624.     if (fp) {
  625.         my_home_document = (char*) malloc(MAX_FILE_NAME);
  626.         status = fgets(my_home_document, MAX_FILE_NAME, fp);
  627.         if (!status) {
  628.             free(my_home_document);
  629.         my_home_document = NULL;
  630.         }
  631.         fclose(fp);
  632.     }
  633.     if (!my_home_document) StrAllocCopy(my_home_document, REMOTE_ADDRESS);
  634.     }
  635.  
  636.     
  637.  
  638. #ifdef unix
  639.  
  640.     if (!my_home_document) {
  641.     FILE * fp = NULL;
  642.     CONST char * home =  (CONST char*)getenv("HOME");
  643.     if (home) { 
  644.         my_home_document = (char *)malloc(
  645.         strlen(home)+1+ strlen(PERSONAL_DEFAULT)+1);
  646.         if (my_home_document == NULL) outofmem(__FILE__, "HTLocalName");
  647.         sprintf(my_home_document, "%s/%s", home, PERSONAL_DEFAULT);
  648.         fp = fopen(my_home_document, "r");
  649.     }
  650.     
  651.     if (!fp) {
  652.         StrAllocCopy(my_home_document, LOCAL_DEFAULT_FILE);
  653.         fp = fopen(my_home_document, "r");
  654.     }
  655.     if (fp) {
  656.         fclose(fp);
  657.     } else {
  658.     if (TRACE) fprintf(stderr,
  659.         "HTBrowse: No local home document ~/%s or %s\n",
  660.         PERSONAL_DEFAULT, LOCAL_DEFAULT_FILE);
  661.         free(my_home_document);
  662.         my_home_document = NULL;
  663.     }
  664.     }
  665. #endif
  666.     ref = HTParse( my_home_document ?    my_home_document :
  667.                 HTClientHost ? REMOTE_ADDRESS
  668.                 : LAST_RESORT,
  669.             "file:",
  670.             PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
  671.     if (my_home_document) {
  672.     if (TRACE) fprintf(stderr,
  673.         "HTAccess: Using custom home page %s i.e. address %s\n",
  674.         my_home_document, ref);
  675.     free(my_home_document);
  676.     }
  677.     anchor = (HTParentAnchor*) HTAnchor_findAddress(ref);
  678.     free(ref);
  679.     return anchor;
  680. }
  681.  
  682.  
  683.